package interview.customListenListAdd;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

/**
 * @author: 李德才
 * @description:
 * @create: 2020-12-12 18:27
 **/
public class Test04_LockSupport {

    // 添加volatile，使t2能够得到通知
    volatile List<Object> lists = new ArrayList<>();

    public void add(Object o) {
        lists.add(o);
    }

    public int size() {
        return lists.size();
    }

    static Thread t1 = null, t2 = null;

    /**
     * t2  先执行，然后锁住自己
     * t1 执行，等 size ==5 时，让 t2 启动，并且让自己停止
     * t2 打印完成之后，让 t1 开始
     */

    /**
     * https://juejin.cn/post/7023021536231555086
     * LockSupport是JDK中比较底层的类，用来创建锁和其他同步工具类的基本线程阻塞原语。
     * java锁和同步器框架的核心 AQS: AbstractQueuedSynchronizer，
     * 就是通过调用 LockSupport .park()和 LockSupport .unpark()实现线程的阻塞和解除阻塞的。
     * LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程，
     * 而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题
     * <p>
     * unpark 可以在  park 之前调用，也就是说，先提供许可。当某线程调用park时，已经有许可了，它就消费这个许可，然后可以继续运行
     * 但是这个“许可”是不能叠加的，“许可”是一次性的。
     * 比如线程B连续调用了三次unpark函数，当线程A调用park函数就使用掉这个“许可”，如果线程A再次调用park，则进入等待状态。
     *
     * @param args
     */

    public static void main(String[] args) {
        Test04_LockSupport c = new Test04_LockSupport();
        t2 = new Thread(() -> {
            LockSupport.park();
            System.out.println("t2 结束");
            LockSupport.unpark(t1);
        }, "t2");
        t1 = new Thread(() -> {
            System.out.println("t1启动");
            for (int i = 0; i < 10; i++) {
                c.add(new Object());
                System.out.println("add " + i);
                if (c.size() == 5) {
                    LockSupport.unpark(t2);
                    LockSupport.park();
                }
            }
        }, "t1");
        t2.start();
        t1.start();
    }

}
